import win32gui
import win32api
import win32con
import pyautogui
import win32ui
import cv2
import numpy as np
import time
import sys
import os
import tkinter as tk
from tkinter import ttk
from threading import Thread
from datetime import datetime, timedelta
import sys
import ntplib
import pytz
import random

# 全局退出标志
exit_flag = False


def resource_path(relative_path):
    """ 获取打包后的资源绝对路径 """
    if getattr(sys, 'frozen', False):
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)


def get_window_handle_by_title(window_title):
    return win32gui.FindWindow(None, window_title)


def get_window_rect(hwnd):
    return win32gui.GetWindowRect(hwnd)


def click_in_window(hwnd, x, y, click_type='left'):
    lParam = win32api.MAKELONG(x, y)
    if click_type == 'left':
        win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam)
        win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, lParam)
    elif click_type == 'right':
        win32gui.PostMessage(hwnd, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, lParam)
        win32gui.PostMessage(hwnd, win32con.WM_RBUTTONUP, 0, lParam)


def get_window_under_mouse():
    x, y = win32api.GetCursorPos()
    hwnd = win32gui.WindowFromPoint((x, y))
    title = win32gui.GetWindowText(hwnd)
    cls_name = win32gui.GetClassName(hwnd)

    # 向上查找顶层窗口句柄
    parent_hwnd = win32gui.GetParent(hwnd)
    while parent_hwnd != 0:
        hwnd = parent_hwnd
        parent_hwnd = win32gui.GetParent(hwnd)

    return hwnd, title, cls_name


def get_network_time():
    """从NTP服务器获取当前网络时间（UTC）"""
    ntp_servers = [
        'pool.ntp.org',
        'cn.pool.ntp.org',
        'time.apple.com'
    ]

    for server in ntp_servers:
        try:
            client = ntplib.NTPClient()
            response = client.request(server, timeout=5)
            network_time = datetime.fromtimestamp(response.tx_time, pytz.utc)
            return network_time
        except Exception as e:
            print(f"服务器 {server} 连接失败: {e}")
    return None


def on_click(event):
    global exit_flag
    hwnd = None
    if event == win32con.WM_LBUTTONDOWN:
        hwnd, title, cls_name = get_window_under_mouse()
        exit_flag = True  # 设置退出标志
    return hwnd


def window_capture(hwnd):
    left, top, right, bottom = win32gui.GetClientRect(hwnd)
    width = right - left
    height = bottom - top

    hwndDC = win32gui.GetWindowDC(hwnd)
    mfcDC = win32ui.CreateDCFromHandle(hwndDC)
    saveDC = mfcDC.CreateCompatibleDC()

    saveBitMap = win32ui.CreateBitmap()
    saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
    saveDC.SelectObject(saveBitMap)

    saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)

    bmp_info = saveBitMap.GetInfo()
    bmp_str = saveBitMap.GetBitmapBits(True)
    img = np.frombuffer(bmp_str, dtype='uint8')
    img = img.reshape((bmp_info['bmHeight'], bmp_info['bmWidth'], 4))

    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, hwndDC)

    return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)


def capture_window(hwnd):
    """截取指定窗口句柄的图像并转为OpenCV格式"""
    # 获取窗口位置和尺寸
    left, top, right, bottom = win32gui.GetClientRect(hwnd)
    width = right - left
    height = bottom - top

    # 创建设备上下文和位图对象
    hwnd_dc = win32gui.GetWindowDC(hwnd)
    mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
    save_dc = mfc_dc.CreateCompatibleDC()
    bitmap = win32ui.CreateBitmap()
    bitmap.CreateCompatibleBitmap(mfc_dc, width, height)
    save_dc.SelectObject(bitmap)

    # 截取窗口内容
    save_dc.BitBlt((0, 0), (width, height), mfc_dc, (0, 0), win32con.SRCCOPY)

    # 转换为numpy数组并处理颜色通道
    img_data = bitmap.GetBitmapBits(True)
    img = np.frombuffer(img_data, dtype=np.uint8).reshape((height, width, 4))
    img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)  # 转换为BGR格式

    # 释放资源
    win32gui.DeleteObject(bitmap.GetHandle())
    save_dc.DeleteDC()
    mfc_dc.DeleteDC()
    win32gui.ReleaseDC(hwnd, hwnd_dc)

    return img


def find_template_in_window(hwnd, template_path, threshold=0.8):
    """改进版：返回区域内随机坐标点"""
    # 修改为资源路径
    resolved_path = resource_path(template_path)
    template = cv2.imread(resolved_path, cv2.IMREAD_GRAYSCALE)
    w, h = template.shape[::-1]  # 获取模板尺寸

    window_img = capture_window(hwnd)
    window_gray = cv2.cvtColor(window_img, cv2.COLOR_BGR2GRAY)

    # 模板匹配
    res = cv2.matchTemplate(window_gray, template, cv2.TM_CCOEFF_NORMED)
    loc = np.where(res >= threshold)

    # 生成随机坐标点
    random_points = []
    for pt in zip(*loc[::-1]):  # 遍历每个匹配位置
        x1, y1 = pt[0], pt[1]
        x2 = x1 + w
        y2 = y1 + h

        # 在匹配区域内生成随机坐标
        rand_x = random.randint(x1, x2)
        rand_y = random.randint(y1, y2)
        random_points.append(rand_x)
        random_points.append(rand_y)
    return random_points


def set_window_size(hwnd, x, y, width, height):
    flags = win32con.SWP_NOZORDER | win32con.SWP_NOACTIVATE
    win32gui.SetWindowPos(hwnd, None, x, y, width, height, flags)


class AutoClickerApp:
    def __init__(self, master):
        self.master = master
        self.running = False
        self.sleep_time = tk.DoubleVar(value=0.3)
        self.vip_code = tk.StringVar()

        self.setup_ui()
        self.hwnd = None
        self.client_left = 0
        self.client_top = 0

    def setup_ui(self):
        master = self.master
        master.title("时空挤号助手 v1.0")
        master.geometry("450x350")

        # 控制面板
        control_frame = ttk.LabelFrame(master, text="控制")
        control_frame.pack(padx=10, pady=5, fill=tk.X)

        self.btn_start = ttk.Button(control_frame, text="启动", command=self.toggle)
        self.btn_start.pack(side=tk.LEFT, padx=5)

        ttk.Button(control_frame, text="退出", command=master.quit).pack(side=tk.RIGHT, padx=5)

        # # 参数设置
        # config_frame = ttk.LabelFrame(master, text="参数配置")
        # config_frame.pack(padx=10, pady=5, fill=tk.X)
        #
        # ttk.Label(config_frame, text="操作间隔（秒）:").pack(side=tk.LEFT)
        # self.entry_sleep = ttk.Entry(config_frame, textvariable=self.sleep_time, width=8)
        # self.entry_sleep.pack(side=tk.LEFT, padx=5)
        # ttk.Button(config_frame, text="恢复默认", command=lambda: self.sleep_time.set(0.3)).pack(side=tk.LEFT)
        # # 密钥
        # ttk.Label(config_frame, text="密钥:").pack(side=tk.LEFT)
        # self.entry_vip_code = ttk.Entry(config_frame, textvariable=self.vip_code, width=18)
        # self.entry_vip_code.pack(side=tk.LEFT, padx=10)

        # 参数设置
        config_frame = ttk.LabelFrame(master, text="参数配置")
        config_frame.pack(padx=10, pady=5, fill=tk.X)

        # 第一行：操作间隔
        row1_frame = ttk.Frame(config_frame)
        row1_frame.pack(fill=tk.X, pady=2)  # 水平填充

        ttk.Label(row1_frame, text="操作间隔（秒）:").pack(side=tk.LEFT)
        self.entry_sleep = ttk.Entry(row1_frame, textvariable=self.sleep_time, width=8)
        self.entry_sleep.pack(side=tk.LEFT, padx=5)
        ttk.Button(row1_frame, text="恢复默认", command=lambda: self.sleep_time.set(0.3)).pack(side=tk.LEFT)

        # 第二行：密钥
        row2_frame = ttk.Frame(config_frame)
        row2_frame.pack(fill=tk.X, pady=2)  # 水平填充

        ttk.Label(row2_frame, text="密钥:").pack(side=tk.LEFT)
        self.entry_vip_code = ttk.Entry(row2_frame, textvariable=self.vip_code, width=18)
        self.entry_vip_code.pack(side=tk.LEFT, padx=10)

        # 日志面板
        log_frame = ttk.LabelFrame(master, text="运行日志")
        log_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

        self.log_text = tk.Text(log_frame, height=8, state=tk.DISABLED)
        scrollbar = ttk.Scrollbar(log_frame, command=self.log_text.yview)
        self.log_text.configure(yscrollcommand=scrollbar.set)

        self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    def toggle(self):
        if not self.running:
            self.start()
        else:
            self.stop()

    def start(self):
        self.running = True
        self.btn_start.config(text="停止")
        if self.vip_code.get() == "":
            self.log("请输入密钥...")
            self.stop()
            return
        self.checkTime()
        self.log("正在初始化...")
        self.log("请使用鼠标点击对应的游戏窗口...")
        try:
            while not exit_flag:
                # 检测鼠标左键按下
                if win32api.GetAsyncKeyState(win32con.VK_LBUTTON) < 0:
                    self.hwnd = on_click(win32con.WM_LBUTTONDOWN)
                    # 等待左键释放
                    while win32api.GetAsyncKeyState(win32con.VK_LBUTTON) < 0 and not exit_flag:
                        time.sleep(0.01)
                time.sleep(0.05)
            # 初始化窗口位置
            set_window_size(self.hwnd, 0, 0, 640, 512)
            self.client_left, self.client_top = win32gui.ClientToScreen(self.hwnd, (0, 0))
            self.log(f"窗口位置初始化成功 ({self.client_left}, {self.client_top})")
            self.log(f"窗口句柄: {self.hwnd}")
        except Exception as e:
            self.log(f"窗口初始化失败: {str(e)}")
            self.stop()
            return

        # 启动工作线程
        self.worker = Thread(target=self.run_automation)
        self.worker.daemon = True
        self.worker.start()

    def stop(self):
        global exit_flag
        self.running = False
        exit_flag = False
        self.btn_start.config(text="启动")
        self.log("操作已停止")

    def run_automation(self):
        try:
            while self.running:
                self.log("开始自动排队操作！")
                dengluyouxi = find_template_in_window(self.hwnd, "pk/image/watu/shiyong.png")
                if dengluyouxi:
                    dengluyouxi_x = dengluyouxi[0] - self.client_left
                    dengluyouxi_y = dengluyouxi[1] - self.client_top
                    print("找到图片", dengluyouxi[0], dengluyouxi[1], self.client_left, self.client_top)
                    click_in_window(self.hwnd,  dengluyouxi[0], dengluyouxi[1])
                    self.sleep(0.5)
        except Exception as e:
            self.log(f"发生错误: {str(e)}")
            self.stop()

    def sleep(self, custom_time=None):
        sleep_time = custom_time if custom_time else self.sleep_time.get()
        time.sleep(max(0.1, sleep_time))  # 最低0.1秒防止误操作

    def log(self, message):
        self.log_text.config(state=tk.NORMAL)
        self.log_text.insert(tk.END, f"[{time.strftime('%H:%M:%S')}] {message}\n")
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)
        self.master.update()

    def checkTime(self):
        # 获取网络时间
        utc_time = get_network_time()
        if not utc_time:
            sys.exit("错误：无法获取网络时间，程序终止")

        # 转换为北京时间
        beijing_tz = pytz.timezone('Asia/Shanghai')
        beijing_time = utc_time.astimezone(beijing_tz)

        # 设置时间范围（2024-02-15 00:00:00 至 2024-02-22 00:00:00）
        start_date = beijing_tz.localize(datetime(2025, 3, 28))
        if self.vip_code.get() == "mh001":
            end_date = start_date + timedelta(days=31)
        elif self.vip_code.get() == "tp001":
            end_date = start_date + timedelta(days=7)
        else:
            self.log("请输入正确的密钥！")
            self.stop()
        # 检查时间范围
        if not (start_date <= beijing_time < end_date):
            self.log(f"已超过体验时间,请联系作者！")
            self.stop()
        self.log(f"体验到期时间:{end_date.strftime('%Y-%m-%d')}")


if __name__ == "__main__":
    root = tk.Tk()
    app = AutoClickerApp(root)
    root.mainloop()
